﻿using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Tradukisto.Engine.ResourceProviders;
using Tradukisto.Engine.Utilities;


namespace Tradukisto.Engine.Helpres
{
    public static partial class DropDownList
    {
        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name)
        {
            return EnumDropDownList<TEnum>(htmlHelper, name, null /* optionLabel */, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, string optionLabel)
        {
            return EnumDropDownList<TEnum>(htmlHelper, name, optionLabel, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList)
        {
            return EnumDropDownList<TEnum>(htmlHelper, name, null /* optionLabel */, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, object htmlAttributes)
        {
            return EnumDropDownList<TEnum>(htmlHelper, name, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, IDictionary<string, object> htmlAttributes)
        {
            return EnumDropDownList<TEnum>(htmlHelper, name, null /* optionLabel */, htmlAttributes);
        }

        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, string optionLabel, object htmlAttributes)
        {
            return EnumDropDownList<TEnum>(htmlHelper, name, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, string name, string optionLabel, IDictionary<string, object> htmlAttributes)
        {
            IEnumerable<SelectListItem> selectList = GetSelectListItems<TEnum>();
            return htmlHelper.DropDownList(name, selectList, optionLabel, htmlAttributes);
        }



        //
        //
        // Specifying Resource type
        //
        //

        public static MvcHtmlString EnumDropDownList<TEnum, TResource>(this HtmlHelper htmlHelper, string name)
        {
            return EnumDropDownList<TEnum, TResource>(htmlHelper, name, null /* optionLabel */, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList<TEnum, TResource>(this HtmlHelper htmlHelper, string name, string optionLabel)
        {
            return EnumDropDownList<TEnum, TResource>(htmlHelper, name, optionLabel, null /* htmlAttributes */);
        }

        public static MvcHtmlString EnumDropDownList<TEnum, TResource>(this HtmlHelper htmlHelper, string name, object htmlAttributes)
        {
            return EnumDropDownList<TEnum, TResource>(htmlHelper, name, null /* optionLabel */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString EnumDropDownList<TEnum, TResource>(this HtmlHelper htmlHelper, string name, IDictionary<string, object> htmlAttributes)
        {
            return EnumDropDownList<TEnum, TResource>(htmlHelper, name, null /* optionLabel */, htmlAttributes);
        }

        public static MvcHtmlString EnumDropDownList<TEnum, TResource>(this HtmlHelper htmlHelper, string name, string optionLabel, object htmlAttributes)
        {
            return EnumDropDownList<TEnum, TResource>(htmlHelper, name, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString EnumDropDownList<TEnum, TResource>(this HtmlHelper htmlHelper, string name, string optionLabel, IDictionary<string, object> htmlAttributes)
        {
            IEnumerable<SelectListItem> selectList = GetSelectListItems<TEnum>();

            return htmlHelper.DropDownList(name, selectList, optionLabel, htmlAttributes);
        }



        #region Private methods

        /// <summary>
        /// Gets the select list items.
        /// </summary>
        /// <typeparam name="TEnum">The type of the enum.</typeparam>
        /// <param name="selectList">The select list.</param>
        /// <param name="resourceType">Type of the resource.</param>
        /// <returns></returns>
        private static IEnumerable<SelectListItem> GetSelectListItems<TEnum>()
        {
            bool isEnum = IsEnum<TEnum>();

            if (!isEnum)
                throw new ArgumentException("TEnum must be an enumerated type");

            var repositoryData = LocalizationProvider.Current.GetAllStringsByControllerAndAction(LocalizationConstants.LISTS_CONTROLLER_NAME, typeof(TEnum).Name);

            List<SelectListItem> ret = new List<SelectListItem>(0);
            foreach (var item in repositoryData)
            {
                ret.Add(new SelectListItem { Text = item.Value, Value = item.Key });

            }

            return ret;
        }

        private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
        {
            Type realModelType = modelMetadata.ModelType;

            Type underlyingType = Nullable.GetUnderlyingType(realModelType);
            if (underlyingType != null)
            {
                realModelType = underlyingType;
            }
            return realModelType;
        }

        #endregion

        /// <summary>
        /// Returns true if a type is an enumerable 
        /// </summary>
        /// <typeparam name="T">Generic type argument</typeparam>
        /// <returns></returns>
        private static bool IsEnum<T>()
        {
            return GetUnderlyingType<T>().IsEnum;
        }

        /// <summary>
        /// Returns the underlying type of the specified nullable type
        /// </summary>
        /// <typeparam name="T">The underlying value type</typeparam>
        private static Type GetUnderlyingType<T>()
        {
            Type realModelType = typeof(T);
            Type underlyingType = Nullable.GetUnderlyingType(realModelType);

            if (underlyingType != null)
                return underlyingType;

            return realModelType;
        }
    }
}
